/**
 * 监听DOM树的更改，不重复监听多个DOM，只一个。
 * @element_ 要监听的DOM树。可以调用 setElement() 方法设置。
 * @fn_ 这是监听DOM树更改后执行的默认函数，可以调用 setFn() 方法设置。如果不传递该值，则默认使用已有的模块方法，但是要设置对应的模块方法，不然相当不起作用。
 **/
var mutation = function (element_ = null, fn_ = null) {
    var observerInit_ = { // 默认配置
        // 设为 `true` 以将监视范围扩展至目标节点整个节点树中的所有节点。
        subtree: true,
        // 设为 `true` 以监视目标节点（如果 `subtree` 为 `true`，则包含子孙节点）添加或删除新的子节点。
        childList: false,
        // 设为 `true` 以监视指定目标节点或子节点树中节点所包含的字符数据的变化。
        characterData: '',
        // 设为 `true` 以在文本在受监视节点上发生更改时记录节点文本的先前值。
        characterDataOldValue: '',
        // 设为 `true` 以观察受监视元素的属性值变更。
        attributes: true, // 设置默认监听所有属性
        // 要监视的特定属性名称的**数组**。如果未包含此属性，则对所有属性的更改都会触发变动通知。
        attributeFilter: '',
        // 当监视节点的属性改动时，将此属性设为 `true` 将记录任何有改动的属性的上一个值。
        // attributeOldValue: ''
        attributeOldValue: true
    };

    /**
     * javascript判断参数是否为dom元素
     * @obj {all} 所有类型
     * @return {Boolean} 如果是DOM元素，则返回true，否则返回false
     **/
    function isDom(obj) {
        return (typeof HTMLElement === 'object') ? obj instanceof HTMLElement : obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
    }
    var fn = fn_ ? fn_ : defaultFn_, // 回调函数
        element = element_; // 要监听的目标


    function defaultFn_(mutationList, observer) {
        mutationList.forEach(mutation_ => {
            console.log('mutation', mutation_);
            switch (mutation_.type) {
                case 'characterData':
                    /**
                     * @target  是一个文本节点，为更改的那个文本节点
                     **/
                    targetFn_(mutation_.target, mutation_.oldValue, mutation_)
                    break;
                case 'childList':
                    targetFn_(mutation_.target, null, mutation_)
                    break;
                case 'attributes':
                    switch (mutation_.attributeName) {
                        case 'style':
                            // console.log('修改的是style');
                            // console.log('修改之前的值为:', mutation.oldValue);
                            // console.log('修改的对象为:', mutation.target);
                            targetFn_(mutation_.target, mutation_.oldValue, mutation_)
                            break;
                        case 'class':
                            targetFn_(mutation_.target, mutation_.oldValue, mutation_)
                            break;
                        case 'id':
                            targetFn_(mutation_.target, mutation_.oldValue, mutation_)
                            break;
                        default:
                            targetFn_(mutation_.target, mutation_.oldValue, mutation_)
                            break;
                    }
                    break;
            }
        })
    }
    /**
     * 默认执行的对应模块的函数
     * @oldValue Dom元素更改之前的值
     * @target 更改的Dom对象
     * @mutation_ 一个mutation对象
     **/
    targetFn_ = function (target, oldValue, mutation_) {};

    class MutationObserver_ {
        constructor() {
            this.observer = null
            this.init_()
        }
        init_() {
            this.observer = new MutationObserver(fn);
            // if (!fn) return alert("请设置回调函数，使用setFn(element_)方法");
            if (!element) return console.warn("请监听目标，使用setElement(Dom)方法");
            if (!isDom(element)) return console.error(`该 ${element} 参数不是DOM元素，而是 ${typeof element} 类型。请使用setElement(Dom)方法设置监听目标或重新使用mutation方法。`);
            this.observer.observe(element, this.getMutationObserverInit());
        }
        // 获取配置
        getMutationObserverInit() {
            var init_ = Object.keys(observerInit_);
            var observerInit__ = {}
            init_.forEach(function (item) {
                // console.log('item', item)
                if (observerInit_[item] !== '') {
                    observerInit__[item] = observerInit_[item]
                }
            })
            return observerInit__;
        }
        // 关闭监听器
        disconnect() {
            this.observer.disconnect();
        }
        // 每次设置新的参数，都重启一次
        restart() {
            if (!element) return console.warn("请监听目标，使用setElement(Dom)方法");
            if (!isDom(element)) return console.error(`该 ${element} 参数不是DOM元素，而是 ${typeof element} 类型。请使用setElement(Dom)方法设置监听目标或重新使用mutation方法。`);
            this.disconnect();
            this.observer.observe(element, this.getMutationObserverInit())
        }

        // ============ 设置模块
        setFnId(fn_) { // 监听元素id的更改
            targetFn_ = fn_
            this.restart()
        }
        setFnClass(fn_) { // 监听元素class的更改
            targetFn_ = fn_
            this.restart()
        }
        setFnStyle(fn_) { // 监听元素style的更改
            targetFn_ = fn_
            this.restart()
        }
        setFnAttributes(fn_) { // 监听元素所有属性的更改 
            targetFn_ = fn_
            this.restart()
        }
        setFnCharacterData(fn_) { // 监听文本元素的更改 
            targetFn_ = fn_
            observerInit_.characterData = true;
            observerInit_.characterDataOldValue = true;
            this.restart()
        }
        setFnChildList(fn_) { // 监听元素添加或删除更改 
            targetFn_ = fn_
            observerInit_.childList = true;
            this.restart()
        }

        // ============= 设置值
        setFn(fn_) {
            fn = fn_
            this.restart()
        }
        getFn() {
            return fn;
        }
        setElement(element_) {
            element = element
            this.restart()
        }
        getElement() {
            return element;
        }
        setSubtree(subtree_) {
            observerInit_.subtree = subtree_
            this.restart()
        }
        getSubtree() {
            return observerInit_.subtree;
        }
        setChildList(childList_) {
            observerInit_.childList = childList_
            this.restart()
        }
        getChildList() {
            return observerInit_.childList;
        }
        setCharacterData(characterData_) {
            observerInit_.characterData = characterData_
            this.restart()
        }
        getCharacterData() {
            return observerInit_.characterData;
        }
        setCharacterDataOldValue(characterDataOldValue_) {
            observerInit_.characterDataOldValue = characterDataOldValue_
            this.restart()
        }
        getCharacterDataOldValue() {
            return observerInit_.characterDataOldValue;
        }
        setAttributes(attributes_) {
            observerInit_.attributes = attributes_
            this.restart()
        }
        getAttributes() {
            return observerInit_.attributes;
        }
        setAttributeFilter(attributeFilter_) {
            observerInit_.attributeFilter = attributeFilter_
            this.restart()
        }
        getAttributeFilter() {
            return observerInit_.attributeFilter;
        }
        setAttributeOldValue(attributeOldValue_) {
            observerInit_.attributeOldValue = attributeOldValue_
            this.restart()
        }
        getAttributeOldValue() {
            return observerInit_.attributeOldValue;
        }
    }
    return new MutationObserver_();
}